//
// Created by denglibin on 19-4-9.
//
/**
 * perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)。参数 s 所指的字符串会先打印出，后面再加上错误原因字符串。
 * 此错误原因依照全局变量errno的值来决定要输出的字符串。
    在库函数中有个errno变量，每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时，该函数已经重新设置了errno的值。
    perror函数只是将你输入的一些信息和现在的errno所对应的错误一起输出。
 *
 *
 *
 * open 函数用于打开和创建文件。以下是 open 函数的简单描述
 * #include <fcntl.h>
    int open (const char *name, int flags);
    int open (const char *name, int flags, mode_t mode);
    返回值：成功则返回文件描述符，否则返回 -1

对于 open 函数来说，第三个参数（...）仅当创建新文件时才使用，用于指定文件的访问权限位（access permission bits）。
 pathname 是待打开/创建文件的路径名（如 C:/cpp/a.cpp）；oflag 用于指定文件的打开/创建模式，这个参数可由以下常量（定义于 fcntl.h）通过逻辑或构成。
O_RDONLY　　只读模式
O_WRONLY　　只写模式
O_RDWR　　读写模式

 打开/创建文件时，至少得使用上述三个常量中的一个。以下常量是选用的：
O_APPEND　　每次写操作都写入文件的末尾
O_CREAT　　如果指定文件不存在，则创建这个文件
O_EXCL　　如果要创建的文件已存在，则返回 -1，并且修改 errno 的值
O_TRUNC　　如果文件存在，并且以只写/读写方式打开，则清空文件全部内容
O_NOCTTY　　如果路径名指向终端设备，不要把这个设备用作控制终端。
O_NONBLOCK　　如果路径名指向 FIFO/块文件/字符文件，则把文件的打开和后继 I/O设置为非阻塞模式（nonblocking mode）
 以下三个常量同样是选用的，它们用于同步输入输出
O_DSYNC　　等待物理 I/O 结束后再 write。在不影响读取新写入的数据的前提下，不等待文件属性更新。
O_RSYNC　　read 等待所有写入同一区域的写操作完成后再进行
O_SYNC　　等待物理 I/O 结束后再 write，包括更新文件属性的 I/O

参数3（mode）
mode：如果文件被新建，指定其权限为mode
mode是八进制权限码，0777表示文件所有者，该文件用户组，其他用户都有可读可写可执行权限
                 0644 所有者可以写，其他用户只能读


open 返回的文件描述符一定是最小的未被使用的描述符。
如果 NAME_MAX（文件名最大长度，不包括'\0'）是 14，而我们想在当前目录下创建文件名长度超过 14 字节的文件，
 早期的 System V 系统（如 SVR2）会截断超出部分，只保留前 14 个字节；
 而由 BSD 衍生的（BSD-derived）系统会返回错误信息，并且把 errno 置为 ENAMETOOLONG。
 POSIX.1 引入常量 _POSIX_NO_TRUNC 用于决定是否截断长文件名/长路径名。如果_POSIX_NO_TRUNC 设定为禁止截断，
 并且路径名长度超过 PATH_MAX（包括 '\0'），或者组成路径名的任意文件名长度超过 NAME_MAX，则返回错误信息，
 并且把 errno 置为 ENAMETOOLONG。


 close(fd)，
调用close()函数可以关闭一个打开的文件。
调用成功返回0，出错返回-1，并设置errno；
注：当一个进程终止时，该进程打开的所有文件都由内核自动关闭；

 隐式回收：当进程结束时，所有打开的文件会被关闭，申请的内存会被释放。
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>


static int main_(){
    int fd;
    char * path = "/home/denglibin/open.txt";
    fd = open(path, O_RDONLY | O_CREAT | O_TRUNC, 0644); // fd = 3 (0,1,2 表示 STDIN, STDOUT,ERROUT 每个进程默认都包含这三个)
    if(fd == -1){
        perror("open");
        return -1;
    }
    printf("open success fd = %d\n", fd);
    //close()会让数据写回磁盘，并释放该文件占用的资源，参数fd是有open或create函数返回的文件描述符 成功返回0 错误返回-1
    int r = close(fd);
    if(r == -1){
        if(errno == EBADF){ //错误码EBADF表示非有效的文件描述符或该文件已经关闭
            printf("不是有效文件描述符号");
        }
        perror("close");
    }
    return 0;
}
